/*******************************************************************************
 * Copyright (c) 2018 xxxxxx Corp.
 *
 * All rights reserved.
 *
 * Contributors:
 *    mfqing - initial,20190823
 *******************************************************************************/

/**
 * @file    snmplib.c
 * @brief   .
 *
 */

/*===========================================================================*/
/* standard headers.                                                   */
/*===========================================================================*/
#include "my_include.h"

/*===========================================================================*/
/* local headers.                                                            */
/*===========================================================================*/

/*===========================================================================*/
/* macros.                                                                   */
/*===========================================================================*/

/*===========================================================================*/
/* constants.                                                                */
/*===========================================================================*/

/*===========================================================================*/
/* local definitions.                                                        */
/*===========================================================================*/

/*===========================================================================*/
/* exported variables.                                                       */
/*===========================================================================*/

/*===========================================================================*/
/* local functions.                                                          */
/*===========================================================================*/




u8 idLen=0;


static uint32_t Str2int(const char *ostr)
{
	uint32_t id = 0;
	char *pcurr;
	pcurr = (char *)ostr;
	if (*pcurr == '.'){
		pcurr++;
	}
	id = atoi(pcurr);
	return id;
}
static uint8_t int2BERBuff(const uint32_t mint, uint8_t buff[])
{
	uint8_t i = 0;
	uint32_t value = mint;
	if (value < 128){
		value %= 128;
		buff[i++] = value;
	}
	else if (value < 128*128){
		buff[i++] = (value / 128) | 0x80;
		value %= 128;
		buff[i++] = value;
	}
	else if (value < 128*128*128){
		buff[i++] = (value / 128 /128) | 0x80;
		value %= 128*128;
		buff[i++] = (value / 128) | 0x80;
		value %= 128;
		buff[i++] = value;
	}
	else if (value < 128*128*128*128){
		buff[i++] = (value / 128 / 128 / 128) | 0x80;
		value %= 128*128*128;
		buff[i++] = (value / 128/128) | 0x80;
		value %= 128*128;
		buff[i++] = (value / 128) | 0x80;
		value %= 128;
		buff[i++] = value;
	}
	return i;
}
static uint8_t int2buff(const uint32_t mint, uint8_t buff[])
{
	uint8_t i = 0;
	uint32_t value = mint;
//	if(value < 128)
//	{
//			buff[i++] = value;
//	}    
	if(value < 256)
	{
		buff[i++] = 0;
		buff[i++] = value;
	}
	else if(value < 256*256){
		buff[i++] = value >> 8;
		buff[i++] = value &  0xFF;
	}
	else if(value < 128*128*128){
		buff[i++] = value >> 16;
		buff[i++] = value >> 8;
		buff[i++] = value &  0xFF;
	}
	else if(value < 128*128*128*128){
		buff[i++] = value >> 24;
		buff[i++] = value >> 16;
		buff[i++] = value >> 8;
		buff[i++] = value &  0xFF;
	}
	return i;
}

static uint8_t BERBuff2int(const uint8_t buff[], const uint8_t len, uint32_t *value)
{
	*value = 0;
	uint8_t i;
	for(i = 0; i < len; i++){
		*value += buff[i] & 0x7F;
		if (buff[i] & 0x80){
			*value *= 128;
		}
		else{
			i++;
			break;
		}
	}
	return i;
}
static uint16_t oidName2Buff(const char *ostr, uint8_t data[])
{
	uint32_t id[SNMP_MAX_OID];
	uint8_t cnt=0;
	uint8_t i,j;
	char *pcurr;
	pcurr = (char *)ostr;
	i = 0;
	while(pcurr != NULL){
		id[i++] = Str2int(pcurr);
		pcurr = strchr(pcurr+1, '.');
		cnt++;
	}
	i = 0;
	if(cnt >= 2){
		data[i++] = id[0]*40 + id[1];
		for (j = 2; j < cnt; j++){
				i += int2BERBuff(id[j], data+i);
		}
	}
	else if(cnt ==1){
		data[i++] = id[0];
	}
	return i;
}
static uint16_t parseLength(const uint8_t *msg, uint16_t *len)
{
	uint16_t i=1;

	if (msg[0] & 0x80){
		int32_t tlen = (msg[0] & 0x7f) - 1;
		*len = msg[i++];
		while (tlen--){
			*len <<= 8;
			*len |= msg[i++];
		}
	}
	else{
		*len = msg[0];
	}

	return i;
}
static bool checkTLV(const tlv_t *tlv)
{
	switch(tlv->tag){
		case VALTYPE_BOOL:
		case VALTYPE_INT:
		case VALTYPE_OCTSTR:
		case VALTYPE_NULL:
		case BTAG_OBJID:
		case VALTYPE_ENUM:
		case BTAG_SEQ:
		case BTAG_SETOF:
		case VALTYPE_IPADDR:
		case BTAG_COUNTER:
		case BTAG_GAUGE:
		case VALTYPE_TIMETICKS:
		case BTAG_OPAQUE:
		case PDUTYPE_GET:
		case PDUTYPE_GETNEXT:
		case PDUTYPE_RESP:
		case PDUTYPE_SET:
		case PDUTYPE_TRAP_V1:
		case PDUTYPE_TRAP_V2C:{
			return TRUE;
		}
	}
	return FALSE;
}
static uint16_t Buff2TLV(const uint8_t buff[], uint16_t len, tlv_t *tlv)
{
	uint16_t idx = 0;
	uint16_t tsize = 0;

	tlv->tag = buff[idx++];
	idx += parseLength(buff+idx, &tlv->len);
	if ((idx + tlv->len) <= len){
		memcpy(tlv->data, buff+idx, tlv->len);
		tsize = idx + tlv->len;
	}
	return tsize;
}
static uint16_t TLV2Buff(const tlv_t *tlv, uint8_t buff[])
{
	uint16_t i = 0;
	buff[i++] = tlv->tag;
	if(tlv->len <= 0x7F){
		buff[i++] = tlv->len;
	}
	else{
		if(tlv->len <= 0xFF){
			buff[i++] = 0x80 | 1;
			buff[i++] = tlv->len;
		}
		else if(tlv->len < 0xFFFF){
			buff[i++] = 0x80 | 2;
			buff[i++] = tlv->len >> 8;
			buff[i++] = tlv->len & 0xFF;
		}
	}
	memcpy(buff+i, tlv->data, tlv->len);
	i += tlv->len;
	return i;
}
static void setBool2TLV(const bool value, tlv_t *tlv)
{
	tlv->tag = VALTYPE_BOOL;
	tlv->len = int2BERBuff(value, tlv->data);
}
static void setInteger2TLV(const uint32_t value, tlv_t *tlv)
{
	tlv->tag = VALTYPE_INT;
	tlv->len = int2buff(value, tlv->data);
}
static void setString2TLV(const char *str, tlv_t *tlv)
{
	uint16_t len;
	len = strlen(str);
	tlv->tag = VALTYPE_OCTSTR;
	tlv->len = MIN(len, SNMP_MAX_STRING);
	memcpy(tlv->data, str, len);
}
static void setNull2TLV(tlv_t *tlv)
{
	tlv->tag = VALTYPE_NULL;
	tlv->len = 0;
}
static void setOidName2TLV(const char *oidname, tlv_t *tlv)
{
	tlv->tag = BTAG_OBJID;
	tlv->len = oidName2Buff(oidname, tlv->data);
}
static void setVersion2TLV(const uint8_t ver, tlv_t *tlv)
{
	setInteger2TLV(ver, tlv);
}
static void setCommunity2TLV(const char *cstr, tlv_t *tlv)
{
	setString2TLV(cstr, tlv);
}
static void setEnterprise2TLV(const char *enterprise, tlv_t *tlv)
{
	tlv->tag = BTAG_OBJID;
	tlv->len = oidName2Buff(enterprise, tlv->data);
}
static void setIpaddr2TLV(const uint8_t *ipaddr, tlv_t *tlv)
{
	uint8_t i;
	tlv->tag = VALTYPE_IPADDR;
	tlv->len = 4;
	for (i = 0; i < tlv->len; i++){
		tlv->data[i] = ipaddr[i];
	}
}
static void setTrapType2TLV(const uint8_t type, tlv_t *tlv)
{
	setInteger2TLV(type, tlv);
}
static void setTrapSpecific2TLV(const uint8_t specific, tlv_t *tlv)
{
	setInteger2TLV(specific, tlv);
}
static void setErrorState2TLV(const uint8_t state, tlv_t *tlv)
{
	setInteger2TLV(state, tlv);
}
static void setErrorIndex2TLV(const uint8_t index, tlv_t *tlv)
{
	setInteger2TLV(index, tlv);
}

static void setTimestamp2TLV(const uint32_t timetick, tlv_t *tlv)
{
	tlv->tag = VALTYPE_TIMETICKS;
	if (timetick > 0xFFFFFF){
		tlv->len = 4;
		tlv->data[0] = timetick >> 24;
		tlv->data[1] = timetick >> 16;
		tlv->data[2] = timetick >> 8;
		tlv->data[3] = timetick >> 0;
	}
	else if (timetick >0xFFFF){
		tlv->len = 3;
		tlv->data[0] = timetick >> 16;
		tlv->data[1] = timetick >> 8;
		tlv->data[2] = timetick >> 0;
	}
	else if (timetick > 0xFF){
		tlv->len = 2;
		tlv->data[0] = timetick >> 8;
		tlv->data[1] = timetick >> 0;
	}
	else{
		tlv->len = 1;
		tlv->data[0] = timetick >> 0;
	}
}

static void setRequestId2TLV(const uint16_t id, tlv_t *tlv)
{
	tlv->tag = VALTYPE_INT;
	tlv->len = 2;
	tlv->data[0] = id >> 8;
	tlv->data[1] = id >> 0;
}
static void setOneVarBind2TLV(const variable_t *variable, tlv_t *tlv)
{
	tlv_t tmp;
	uint16_t i;
	i = 0;
	tlv->tag = BTAG_SEQ;
	// oid name
	memset(&tmp, 0, sizeof(tmp));
	setOidName2TLV(variable->name, &tmp);
/*
	if (variable->value.type == VALTYPE_IPADDR){
			tmp.data[tmp.len++] = variable->value.data.ipaddr[0];
			tmp.data[tmp.len++] = variable->value.data.ipaddr[1];
			tmp.data[tmp.len++] = variable->value.data.ipaddr[2];
			tmp.data[tmp.len++] = variable->value.data.ipaddr[3];
	}
*/
	i += TLV2Buff(&tmp, tlv->data+i);
	// oid value
	memset(&tmp, 0, sizeof(tmp));
	switch(variable->value.type){
		case VALTYPE_BOOL:{
			memset(&tmp, 0, sizeof(tmp));
			setBool2TLV(variable->value.data.tbool, &tmp);
			i += TLV2Buff(&tmp, tlv->data+i);
			break;
		}
		case VALTYPE_INT:{
			memset(&tmp, 0, sizeof(tmp));
			setInteger2TLV(variable->value.data.tint, &tmp);
			i += TLV2Buff(&tmp, tlv->data+i);
			break;
		}
		case VALTYPE_OCTSTR:{
			memset(&tmp, 0, sizeof(tmp));
			setString2TLV(variable->value.data.octstr, &tmp);
			i += TLV2Buff(&tmp, tlv->data+i);
			break;
		}
		case VALTYPE_OBJID:{
			memset(&tmp, 0, sizeof(tmp));
			setOidName2TLV(variable->value.data.oid, &tmp);
			i += TLV2Buff(&tmp, tlv->data+i);
			break;
		}
		case VALTYPE_NULL:{
			memset(&tmp, 0, sizeof(tmp));
			setNull2TLV(&tmp);
			i += TLV2Buff(&tmp, tlv->data+i);
			break;
		}
		case VALTYPE_TIMETICKS:{
			memset(&tmp, 0, sizeof(tmp));
			setTimestamp2TLV(variable->value.data.timetick, &tmp);
			i += TLV2Buff(&tmp, tlv->data+i);
			break;
		}
		case VALTYPE_IPADDR:{
			memset(&tmp, 0, sizeof(tmp));
			setIpaddr2TLV(variable->value.data.ipaddr, &tmp);
			i += TLV2Buff(&tmp, tlv->data+i);
			break;
		}
		case VALTYPE_ENUM:{
			memset(&tmp, 0, sizeof(tmp));
			break;
		}
		default:{
			break;
		}
	}
	// tlv length
	tlv->len = i;
}

static void setVariableBindings2TLV(const variable_t variables[], uint8_t varcnt, tlv_t *tlv)
{
	tlv_t tmp;
	uint16_t i, j;
	tlv->tag = BTAG_SEQ;
	i = 0;
	for (j = 0; j < varcnt; j++){
		memset(&tmp, 0, sizeof(tmp));
		setOneVarBind2TLV(&variables[j], &tmp);
		i += TLV2Buff(&tmp, tlv->data + i);
	}
	tlv->len = i;
}

static void setPDU2TLV(const pdu_t *pdu, tlv_t *tlv)
{
	uint16_t i = 0;
	u8 n=0;
	tlv_t tmp;

	tlv->tag = pdu->type;
	if((pdu->type == PDUTYPE_GET) || (pdu->type == PDUTYPE_GETNEXT) ||
		 (pdu->type == PDUTYPE_SET) || (pdu->type == PDUTYPE_RESP)    ||
		 (pdu->type == PDUTYPE_TRAP_V2C)){
		// requestid		//2022.5.7
		memset(&tmp, 0, sizeof(tmp));
		if(idLen){
			tmp.tag = VALTYPE_INT;
			tmp.len = idLen;
			for(n=0;n<idLen;n++){
				tmp.data[n] = (u8)(pdu->requestid >> (8*(idLen-n-1)));
			}
			idLen=0;
		}else	setRequestId2TLV(pdu->requestid, &tmp);
		
		i += TLV2Buff(&tmp, tlv->data + i);
		// errstate;
		memset(&tmp, 0, sizeof(tmp));
		setErrorState2TLV(pdu->errorstate, &tmp);
		i += TLV2Buff(&tmp, tlv->data + i);
		// errindex;
		memset(&tmp, 0, sizeof(tmp));
		setErrorIndex2TLV(pdu->errorindex, &tmp);
		i += TLV2Buff(&tmp, tlv->data + i);
		// variable binding;
		memset(&tmp, 0, sizeof(tmp));
		setVariableBindings2TLV(pdu->variables, pdu->cnt, &tmp);
		i += TLV2Buff(&tmp, tlv->data + i);
	}
	else if (pdu->type == PDUTYPE_TRAP_V1){
		// enterprise oid
		memset(&tmp, 0, sizeof(tmp));
		setEnterprise2TLV(pdu->variables[1].name, &tmp);
		i += TLV2Buff(&tmp, tlv->data + i);
		// agent ip;
		memset(&tmp, 0, sizeof(tmp));
		setIpaddr2TLV(pdu->variables[1].value.data.ipaddr, &tmp);
		i += TLV2Buff(&tmp, tlv->data + i);
		// trap type;
		memset(&tmp, 0, sizeof(tmp));
		setTrapType2TLV(pdu->traptype, &tmp);
		i += TLV2Buff(&tmp, tlv->data + i);
		// trap specific;
		memset(&tmp, 0, sizeof(tmp));
		setTrapSpecific2TLV(pdu->trapspecific, &tmp);
		i += TLV2Buff(&tmp, tlv->data + i);
		// timestamp;
		memset(&tmp, 0, sizeof(tmp));
		setTimestamp2TLV(pdu->variables[0].value.data.timetick, &tmp);
		i += TLV2Buff(&tmp, tlv->data + i);
		// variable binding;
		memset(&tmp, 0, sizeof(tmp));
		setVariableBindings2TLV(&pdu->variables[2], 1, &tmp);
		i += TLV2Buff(&tmp, tlv->data + i);
	}
	// set tlv length
	tlv->len = i;
}

static int parseTLV(const uint8_t buff[], const uint16_t len, tlv_t *tlv)
{
	int tsize;
	tsize = Buff2TLV(buff, len, tlv);
	if (checkTLV(tlv) == TRUE){
		return tsize;
	}
	return -1;
}

static int parseVersion(const uint8_t data[], const uint16_t len, uint8_t *version)
{
	int tsize = 0; // sizeof TLV
	tlv_t tlv;
	tsize =  parseTLV(data, len, &tlv); //
	if ((tlv.len == 1) && (tlv.tag == VALTYPE_INT)){
		*version = tlv.data[0];
		return tsize;
	}
	return -1;
}

static int parseCommunity(const uint8_t data[], const uint16_t len, char community[])
{
	int tsize = 0; // sizeof TLV
	tlv_t tlv;
	tsize =  parseTLV(data, len, &tlv); //
	if ((tlv.len <= SNMP_MAX_STRING) && (tlv.tag == VALTYPE_OCTSTR)){
		memcpy(community, tlv.data, tlv.len);
		return tsize;
	}
	return -1;
}

static int parseRequestID(const uint8_t data[], const uint16_t len, uint32_t *id)
{
	int tsize = 0; // sizeof TLV
	tlv_t tlv;
	tsize =  parseTLV(data, len, &tlv); //
	idLen = tlv.len;
	if(tlv.tag == VALTYPE_INT && (tlv.len<= 4)){
		int i=0;
		*id=0;
		for(int i=0;i<tlv.len;i++){
			*id = (*id<<8)+tlv.data[i];
		}
		return tsize;
	}
	/*if ((tlv.len <= 2) && (tlv.tag == VALTYPE_INT)){
		*id = tlv.data[0] << 8 | tlv.data[1];
		return tsize;
	}*/
	return -1;
}

static int parseErrorState(const uint8_t data[], const uint16_t len, uint8_t *state)
{
	int tsize = 0; // sizeof TLV
	tlv_t tlv;
	tsize =  parseTLV(data, len, &tlv); //
	if ((tlv.len == 1) && (tlv.tag == VALTYPE_INT)){
		*state = tlv.data[0];
		return tsize;
	}
	return -1;
}

static int parseErrorIndex(const uint8_t data[], const uint16_t len, uint8_t *index)
{
	int tsize = 0; // sizeof TLV
	tlv_t tlv;
	tsize =  parseTLV(data, len, &tlv); //
	if ((tlv.len == 1) && (tlv.tag == VALTYPE_INT)){
		*index = tlv.data[0];
		return tsize;
	}
	return -1;
}

static int parseTrapType(const uint8_t data[], const uint16_t len, uint8_t *type)
{
	int tsize = 0; // sizeof TLV
	tlv_t tlv;
	tsize =  parseTLV(data, len, &tlv); //
	if ((tlv.len == 1) && (tlv.tag == VALTYPE_INT)){
			*type = tlv.data[0];
			return tsize;
	}
	return -1;
}

static int parseTrapSpecific(const uint8_t data[], const uint16_t len, uint8_t *specific)
{
	int tsize = 0; // sizeof TLV
	tlv_t tlv;
	tsize =  parseTLV(data, len, &tlv); //
	if ((tlv.len == 1) && (tlv.tag == VALTYPE_INT)){
		*specific = tlv.data[0];
		return tsize;
	}
	return -1;
}

static int parseOidName(const uint8_t data[], const uint16_t len, char oidname[])
{
	int oidsize = 0; // sizeof TLV
	tlv_t tlv;
	oidsize =  parseTLV(data, len, &tlv); //
	if ((tlv.len <= SNMP_MAX_STRING) && (tlv.tag == BTAG_OBJID)){
		uint8_t *pdata;
		int remainlen;
		int tsize;
		uint32_t oidint;
		pdata = tlv.data;
		remainlen = tlv.len;

		// "1.x"
		sprintf(oidname,"%u.%u", tlv.data[0]/40, tlv.data[0]%40);
		pdata += 1;
		remainlen -= 1;
		// "1.x.?.?.?.?.?"
		while(remainlen > 0){
				tsize = BERBuff2int(pdata, remainlen, &oidint);
				if (tsize < 0){
						return -1;
				}
				sprintf(oidname + strlen(oidname), ".%u", oidint);
				pdata += tsize;
				remainlen -= tsize;
		}
		return oidsize;
	}
	return -1;
}

static bool checkOidValueType(const uint8_t type)
{
	 switch(type){
		 case VALTYPE_BOOL:
		 case VALTYPE_INT:
		 case VALTYPE_OCTSTR:
		 case VALTYPE_OBJID:
		 case VALTYPE_NULL:
		 case VALTYPE_ENUM:
		 case VALTYPE_IPADDR:
		 case VALTYPE_TIMETICKS:{
		 	return TRUE;
		 }
	 }
	 return FALSE;
}

static int parseOidValue(const uint8_t data[], const uint16_t len, value_t *value)
{
	int tsize = 0; // sizeof TLV
	tlv_t tlv;
	tsize =  parseTLV(data, len, &tlv); //
	if (checkOidValueType(tlv.tag) == TRUE){
			value->type = tlv.tag;
			switch(value->type){
					case VALTYPE_BOOL:{
							value->data.tbool = tlv.data[0];
							break;
					}
					case VALTYPE_INT:{
							uint8_t i;
							value->data.tint = 0;
							for (i = 0; i < tlv.len; i++){
									value->data.tint <<= 8;
									value->data.tint |= tlv.data[i];
							}
							break;
					}
					case VALTYPE_OCTSTR:{
							memcpy(value->data.octstr, tlv.data, tlv.len);
							break;
					}
					case VALTYPE_OBJID:{
							parseOidName(tlv.data, tlv.len, value->data.oid);
							break;
					}
					case VALTYPE_NULL:{
							value->data.tnull = 1;
							break;
					}
					case VALTYPE_TIMETICKS:{
							uint8_t i;
							value->data.timetick = 0;
							for (i = 0; i < tlv.len; i++){
									value->data.timetick <<= 8;
									value->data.timetick |= tlv.data[i];
							}
							break;
					}
					case VALTYPE_IPADDR:{
							value->data.ipaddr[0]= tlv.data[0];
							value->data.ipaddr[1] = tlv.data[1];
							value->data.ipaddr[2] = tlv.data[2];
							value->data.ipaddr[3] = tlv.data[3];
							break;
					}
					case VALTYPE_ENUM:{
							break;
					}
					default:{
							break;
					}
			}
			return tsize;
	}
	return -1;
}

static int parseOneVarBind(const uint8_t data[], const uint16_t len, variable_t *variable)
{
	int onevarsize = 0; // sizeof TLV
	tlv_t tlv;
	onevarsize =  parseTLV(data, len, &tlv); //
	if (tlv.tag == BTAG_SEQ){
			uint8_t *pdata;
			int remainlen;
			int tsize;
			pdata = tlv.data;
			remainlen = tlv.len;
			// oid name
			tsize = parseOidName(pdata, remainlen, variable->name);
			if (tsize < 0){
					return -1;
			}
			pdata += tsize;
			remainlen -= tsize;
			// oid value
			tsize = parseOidValue(pdata, remainlen, &variable->value);
			if (tsize < 0){
					return -1;
			}
			pdata += tsize;
			remainlen -= tsize;

			return onevarsize;
	}
	return -1;
}

static int parseVaraibleBindings(const uint8_t data[], const uint16_t len, uint8_t *cnt, variable_t variables[])
{
	int varsize = 0; // sizeof TLV
	uint8_t idx = 0;
	tlv_t tlv;
	varsize =  parseTLV(data, len, &tlv); //
	if (tlv.tag == BTAG_SEQ){
			uint8_t *pdata;
			int remainlen;
			int tsize;
			pdata = tlv.data;
			remainlen = tlv.len;

			while(remainlen > 0){
					tsize = parseOneVarBind(pdata, remainlen, &variables[idx++]);
					if (tsize < 0){
							return -1;
					}
					pdata += tsize;
					remainlen -= tsize;
					*cnt = idx;
			}

			return varsize;
	}

	return -1;
}

static bool checkPDU(const uint8_t type)
{
	switch(type){
	 case PDUTYPE_GET:
	 case PDUTYPE_GETNEXT:
	 case PDUTYPE_RESP:
	 case PDUTYPE_SET:
	 case PDUTYPE_TRAP_V1:
	 case PDUTYPE_TRAP_V2C:{
			return TRUE;
	 }
	}
	return FALSE;
}

static int parsePDU(const uint8_t data[], const uint16_t len, pdu_t *pdu)
{
	int pdusize = 0; // sizeof TLV
	tlv_t tlv;
	pdusize =  parseTLV(data, len, &tlv);
	if(checkPDU(tlv.tag) == TRUE){
		uint8_t *pdata;
		int remainlen;
		int tsize;
		pdata = tlv.data;
		remainlen = tlv.len;

		pdu->type = tlv.tag;
		if ((pdu->type == PDUTYPE_GET) || (pdu->type == PDUTYPE_GETNEXT) ||
				(pdu->type == PDUTYPE_SET) || (pdu->type == PDUTYPE_RESP)    ||
				(pdu->type == PDUTYPE_TRAP_V2C)){
				// request id
				tsize = parseRequestID(pdata, remainlen, &pdu->requestid);
				if (tsize < 0){
						return -1;
				}
				pdata += tsize;
				remainlen -= tsize;
				// errorstate
				tsize = parseErrorState(pdata, remainlen, &pdu->errorstate);
				if (tsize < 0){
						return -1;
				}
				pdata += tsize;
				remainlen -= tsize;
				// errorindex
				tsize = parseErrorIndex(pdata, remainlen, &pdu->errorindex);
				if (tsize < 0){
						return -1;
				}
				pdata += tsize;
				remainlen -= tsize;
				//variables
				tsize = parseVaraibleBindings(pdata, remainlen, &pdu->cnt, pdu->variables);
				if (tsize < 0){
						return -1;
				}
		}
		else if(pdu->type == PDUTYPE_TRAP_V1){
				// enterprise oid
				tsize = parseOidName(pdata, remainlen, pdu->variables[1].name);
				if (tsize < 0){
						return -1;
				}
				pdata += tsize;
				remainlen -= tsize;
				// agent ip;
				tsize = parseOidValue(pdata, remainlen, &pdu->variables[1].value);
				if (tsize < 0){
						return -1;
				}
				pdata += tsize;
				remainlen -= tsize;
				// trap type;
				tsize = parseTrapType(pdata, remainlen, &pdu->traptype);
				if (tsize < 0){
						return -1;
				}
				pdata += tsize;
				remainlen -= tsize;
				// trap specific;
				tsize = parseTrapSpecific(pdata, remainlen, &pdu->trapspecific);
				if (tsize < 0){
						return -1;
				}
				pdata += tsize;
				remainlen -= tsize;
				// timestamp;
				tsize = parseOidValue(pdata, remainlen, &pdu->variables[0].value);
				if (tsize < 0){
						return -1;
				}
				pdata += tsize;
				remainlen -= tsize;
				// variable binding;
				tsize = parseVaraibleBindings(pdata, remainlen, &pdu->cnt, &pdu->variables[2]);
				if (tsize < 0){
						return -1;
				}
				pdu->cnt = 3;
		}
		return pdusize;
	}

	return -1;
}

/*===========================================================================*/
/* exported functions.                                                       */
/*===========================================================================*/
int snmplib_package(const snmp_t *snmp, uint8_t buff[], const uint16_t lenofbuff)
{
	uint16_t i = 0;
	tlv_t tlv;
	if ((SNMP_V1 == snmp->version) || (SNMP_V2C == snmp->version)){
		tlv_t tmp;
		// tlv tag flag
		tlv.tag = SNMP_HEAD;
		// version;
		memset(&tmp, 0, sizeof(tmp));
		setVersion2TLV(snmp->version, &tmp);
		i += TLV2Buff(&tmp, tlv.data + i);
		// community;
		memset(&tmp, 0, sizeof(tmp));
		setCommunity2TLV(snmp->community, &tmp);
		i += TLV2Buff(&tmp, tlv.data + i); 
		// pdu
		memset(&tmp, 0, sizeof(tmp));
		setPDU2TLV(&snmp->pdu, &tmp);
		i += TLV2Buff(&tmp, tlv.data + i);
		// tlv length
		tlv.len = i;
	}
	else if (SNMP_V3 == snmp->version){

	}
	if (lenofbuff > (1+2+tlv.len)){
		return TLV2Buff(&tlv, buff);
	}
	else{
		return -1;
	}
}

int snmplib_parse(const uint8_t buff[], const uint16_t lenofbuff, snmp_t *snmp)
{
	int snmpsize = 0;
	tlv_t tlv;
	snmpsize = parseTLV(buff, lenofbuff, &tlv);
	if (tlv.tag == SNMP_HEAD){
		uint8_t *pdata = tlv.data;
		int remainlen = tlv.len;
		int tsize;
		// version
		tsize = parseVersion(pdata, remainlen, &snmp->version);
		if (tsize < 0){
			return -1;
		}
		pdata += tsize;
		remainlen -= tsize;
		// community
		tsize = parseCommunity(pdata, remainlen, snmp->community);
		if (tsize < 0){
			return -1;
		}
		pdata += tsize;
		remainlen -= tsize;
		// pdu
		tsize = parsePDU(pdata, remainlen, &snmp->pdu);
		if (tsize < 0){
			return -1;
		}
		return snmpsize;
	}
	return -1;
}


